package com.example.isoftlangchainai.rag;

import com.example.isoftlangchainai.rag.naive.NaivePgVectorRagHelper;
import com.example.isoftlangchainai.rag.naive.NaiveRagAssistant;
import com.example.isoftlangchainai.rag.naive.NaiveRagHelper;
import com.example.isoftlangchainai.rag.utils.PgVectorStoreUtils;
import com.example.isoftlangchainai.rag.utils.Utils;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.store.embedding.EmbeddingStore;

/**
 * @Description: [naive Rag]使用向量搜索的原始RAG
 * @Author :chenjun
 */
public class RagAI {
    public static void main(String[] args) {
        //************************一：文档 ******************************
        //1 Document Loader  文档加载器:加载class resources下的文件：智慧城市.xlsx
        //ClassPathDocumentLoader, FileSystemDocumentLoader,UrlDocumentLoader ,GitHubDocumentLoader......
        /* example:
            Document document = ClassPathDocumentLoader.loadDocument("vectorfile/智慧城市.xlsx");
            System.out.println(document.text());

            List<Document> documents = FileSystemDocumentLoader.loadDocuments("D:\\thridFarmework\\JeecgBoot-master\\isoft-langchain-ai\\src\\main\\resources\\vectorfile");
            Document document1 = documents.get(0);
            System.out.println(document1.text());
            System.out.println(document1.metadata());
         */
        // Document Parser档解析器:TextDocumentParser,ApachePdfBoxDocumentParser ,ApachePoiDocumentParser......

        // DocumentTransformer文档转换器

        //2 TextSegment文本段:加载文档后拆分（分块）为更小的片段（块）。

        //3 DocumentSplitter文档拆分器:对文档后拆分（分块），将这些较小的分块（段落、句子、单词等）组合到TextSegment。
        //DocumentByParagraphSplitter段落拆分,DocumentByLineSplitter行拆分,DocumentByWordSplitter字符拆分.....

        //4 TextSegmentTransformer文本段转换器:对TextSegment进行转换，如：将TextSegment转换为向量，将TextSegment转换为Tokens，将TextSegment转换为Tokens的IDs等。

        //************************二：Embedding嵌入 ******************************
        //1 Embedding:嵌入Embedding类封装一个数字向量，表示已嵌入的内容（通常是文本，如TextSegment）的“语义含义”。
        //Embedding.dimension():返回嵌入向量的维度（其长度）,CosineSimilarity.between(Embedding, Embedding):计算 2 个嵌入向量之间的余弦相似度

        //2 EmbeddingModel:嵌入模型, 将文本/TextSegment等转换为Embedding的特殊类型的模型.

        //3 EmbeddingStore:嵌入存储，即Embedding的存储，称为矢量数据库。允许存储和高效搜索相似的（靠近嵌入空间）嵌入。
        // 支持的存储类型有：In-memory、ClickHouse、Elasticsearch、Milvus、PGVector、Redis等
        // 见：https://docs.langchain4j.dev/integrations/embedding-stores/
        /* example:
         *       EmbeddingStore.add(Embedding),将给定的 Embedding添加到store中;
         *       EmbeddingStore.addAll(List<Embedding>),将给定嵌入的列表添加到存储中，并返回随机ID列表;
         *       EmbeddingStore.search(EmbeddingSearchRequest),搜索最相似的嵌入向量;
         *
         */

        //3.1 EmbeddingSearchRequest:嵌入搜索请求对象。
        /** 具有以下属性：
         *       Embedding queryEmbedding：用作引用的嵌入
         *       int maxResults：要返回的最大结果数(默认值:3),可选参数。
         *       double minScore：最低分数，范围从[0,1],默认值:0,将仅返回 score >= minScore的嵌入。
         *       Filter filter过滤器过滤器：在搜索期间应用于Metadata的过滤器。仅返回TextSegment其Metadata与Filter匹配的Filter。
         */
        //3.1.1 Filter过滤器，允许在搜索期间对Metadata进行过滤。
         /** Filter类型：
          *     IsEqualTo、IsNotEqualTo、IsGreaterThan、IsGreaterThanOrEqualTo、IsLessThan、IsLessThanOrEqualTo
          *     IsIn、IsNotIn、ContainsString包含字符串、And和、Not不、Or或;
          */
        //3.2 EmbeddingSearchResult:嵌入搜索结果对象,即EmbeddingStore中搜索的结果，包含EmbeddingMatches的列表。
        //3.2.1 EmbeddingMatch嵌入匹配:表示匹配的Embedding、相关性分数、ID、原始嵌入数据(如TextSegment)

        //3.3 EmbeddingStoreIngestor:嵌入摄取管道,负责将Document摄取到EmbeddingStore。
       /* example:
             EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
                //将每个文档按1000个token为一块进行分割,每块之间保留200个token的重叠，以保证上下文连贯性
                .documentSplitter(DocumentSplitters.recursive(1000, 200, new OpenAiTokenCountEstimator("gpt-4o-mini")))
                .embeddingModel(embeddingModel)
                .embeddingStore(embeddingStore)
                .build();
            ingestor.ingest(document);
            ingestor.ingest(document, document1);
            IngestionResult ingestionResult = ingestor.ingest(List.of(document, document1));
      */

//        naiveRag();
        pgVectorRag();
    }

    /**
     *
     * [描述]:1. [naive Rag],使用向量搜索的原始RAG，向量库采用内存向量库
     */
    public static void naiveRag() {
        NaiveRagHelper naiveRagHelper = new NaiveRagHelper();
        NaiveRagAssistant assistant = naiveRagHelper.createAssistant("vectorfile/智慧城市.xlsx");
        Utils.startConversationWith(assistant);
    }

    /**
     *
     * [描述]:2.文档向量化存储PgVector向量库，完成嵌入Embedding向量搜索
     */
    public static void pgVectorRag() {
        EmbeddingStore<TextSegment> embeddingStore = PgVectorStoreUtils.initPgVector();
        NaivePgVectorRagHelper naivePgVectorRagHelper = new NaivePgVectorRagHelper(embeddingStore);
        NaiveRagAssistant assistant = naivePgVectorRagHelper.createAssistant();
        Utils.startConversationWithPgVector(assistant, embeddingStore);
    }

}
